#include "Detector.h"
#include "tinyxml.h"

#define DONT_JUMP 0

class XMLDetector : public Detector
{
public:
	XMLDetector(std::string inObjectType = "NO CLASSIFIER")
	{
		mXMLDoc = NULL;
		mCurrentFrameNode = NULL;
		mCurrentFrame = -1;

		mObjectType = inObjectType;
		mDetectorType = "XMLDetector";

		mJumpFrame = DONT_JUMP;
		mJumpOffset = 0;
	}
	virtual ~XMLDetector()
	{
		if(mXMLDoc)
			delete mXMLDoc;
	};

	//return number of detected object, return -1 if error
	//Only the frame numbers gonna be usefull (its not inside IplImage)
	//inFrame could be NULL
	virtual int detectObjects(std::vector<cv::Rect>& outDetectedObjects, std::vector<double>& outConfidences, cv::Mat& inFrame);

	//Take control of a XMLDoc created outside
	void setXMLDoc(TiXmlDocument* inXMLDoc){mXMLDoc=inXMLDoc;};
	const TiXmlDocument* const getDATReader(TiXmlDocument* inXMLDoc){return mXMLDoc;};

	//Change the way the detector work
	void setJumpFrame(unsigned short int inJumpFrame){mJumpFrame = inJumpFrame;};
	void dontJump(){mJumpFrame = DONT_JUMP;};

	//if you want it to be created inside
	//it is initialized
	bool createXMLDoc(std::string inXMLFilename)
	{
		mXMLDoc = new TiXmlDocument(inXMLFilename.c_str());
		bool lLoadOkay = mXMLDoc->LoadFile();
		if(lLoadOkay)
		{
			TiXmlNode* lRoot = mXMLDoc->RootElement();
			mCurrentFrameNode = lRoot->FirstChildElement("Frame");
			if(!mCurrentFrameNode)
			{
				std::cerr<<"XML file corrupt " << inXMLFilename<<std::endl;
				return false;
			}
			mCurrentFrame = 0;
		}
		return lLoadOkay;
	};

	bool setFrame(unsigned int inFrame)
	{
		if(mCurrentFrame==-1)
			return false;
		if((int)inFrame<mCurrentFrame)
		{
			while(mCurrentFrame != inFrame)
				if(!previousFrame())
					return false;
		}
		else if((int)inFrame>mCurrentFrame)
		{
			while(mCurrentFrame != (int)inFrame)
				if(!nextFrame())
					return false;
		}
		return true;
	};
	
private:
	bool nextFrame()
	{
		if(mCurrentFrame==-1)
			return false;
		mCurrentFrameNode = mCurrentFrameNode->NextSiblingElement();
		if(!mCurrentFrameNode)
			return false;
		mCurrentFrame++;
		return true;
	};
	bool previousFrame()
	{
		if(mCurrentFrame==-1)
			return false;
		//Exactly like NextSiblingElement() but PreviousSiblingElement() doesnt exist
		TiXmlNode* lNode;
		for (lNode = mCurrentFrameNode->PreviousSibling(); lNode; lNode = lNode->PreviousSibling())
			if (lNode->ToElement())
				break;//mCurrentFrameNode = lNode->ToElement;
		mCurrentFrameNode = lNode->ToElement();
		if(!mCurrentFrameNode)
			return false;
		mCurrentFrame--;
		return true;
	}

	TiXmlDocument*						mXMLDoc;
	TiXmlNode*							mCurrentFrameNode;	
	int									mCurrentFrame;

	unsigned short int					mJumpFrame;	//0 == no, 1 and more --> detect 1 frame / mJumFrame
	unsigned short int					mJumpOffset; //value of 0 and mJumpFrame (not included)
	std::map<int, unsigned int>			mMapIDCounter;
};